home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step04 / supfilesrv.c < prev   
Encoding:
Text File  |  1994-08-02  |  52.4 KB  |  1,855 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  *
  25. /*
  26.  * supfilesrv -- SUP File Server
  27.  *
  28.  * Usage:  supfilesrv [-l] [-P] [-N] [-R]
  29.  *    -l    "live" -- don't fork daemon
  30.  *    -P    "debug ports" -- use debugging network ports
  31.  *    -N    "debug network" -- print debugging messages for network i/o
  32.  *    -R    "RCS mode" -- if file is an rcs file, use co to get contents
  33.  *
  34.  **********************************************************************
  35.  * HISTORY
  36.  * 13-Sep-92  Mary Thompson (mrt) at Carnegie-Mellon University
  37.  *    Changed name of sup program in xpatch from /usr/cs/bin/sup to
  38.  *    /usr/bin/sup for exported version of sup.
  39.  *
  40.  * 7-July-93  Nate Williams at Montana State University
  41.  *    Modified SUP to use gzip based compression when sending files
  42.  *    across the network to save BandWidth
  43.  *
  44.  * $Log: supfilesrv.c,v $
  45.  * Revision 1.5  1993/08/04  17:46:21  brezak
  46.  * Changes from nate for gzip'ed sup
  47.  *
  48.  * Revision 1.3  1993/06/05  21:32:17  cgd
  49.  * use daemon() to put supfilesrv into daemon mode...
  50.  *
  51.  * Revision 1.2  1993/05/24  17:57:31  brezak
  52.  * Remove netcrypt.c. Remove unneeded files. Cleanup make.
  53.  *
  54.  * Revision 1.20  92/09/09  22:05:00  mrt
  55.  *     Added Brad's change to make sendfile take a va_list.
  56.  *     Added support in login to accept an non-encrypted login
  57.  *     message if no user or password is being sent. This supports
  58.  *     a non-crypting version of sup. Also fixed to skip leading
  59.  *     white space from crypts in host files.
  60.  *     [92/09/01            mrt]
  61.  * 
  62.  * Revision 1.19  92/08/11  12:07:59  mrt
  63.  *         Made maxchildren a patchable variable, which can be set by the
  64.  *         command line switch -C or else defaults to the MAXCHILDREN
  65.  *         defined in sup.h. Added most of Brad's STUMP changes.
  66.  *     Increased PGMVERSION to 12 to reflect substantial changes.
  67.  *     [92/07/28            mrt]
  68.  * 
  69.  * Revision 1.18  90/12/25  15:15:39  ern
  70.  *     Yet another rewrite of the logging code. Make up the text we will write
  71.  *        and then get in, write it and get out.
  72.  *     Also set error on write-to-full-disk if the logging is for recording
  73.  *        server is busy.
  74.  *     [90/12/25  15:15:15  ern]
  75.  * 
  76.  * Revision 1.17  90/05/07  09:31:13  dlc
  77.  *     Sigh, some more fixes to the new "crypt" file handling code.  First,
  78.  *     just because the "crypt" file is in a local file system does not mean
  79.  *     it can be trusted.  We have to check for hard links to root owned
  80.  *     files whose contents could be interpretted as a crypt key.  For
  81.  *     checking this fact, the new routine stat_info_ok() was added.  This
  82.  *     routine also makes other sanity checks, such as owner only permission,
  83.  *     the file is a regular file, etc.  Also, even if the uid/gid of th
  84.  *     "crypt" file is not going to be used, still use its contents in order
  85.  *     to cause fewer surprises to people supping out of a shared file system
  86.  *     such as AFS.
  87.  *     [90/05/07            dlc]
  88.  * 
  89.  * Revision 1.16  90/04/29  04:21:08  dlc
  90.  *     Fixed logic bug in docrypt() which would not get the stat information
  91.  *     from the crypt file if the crypt key had already been set from a
  92.  *     "host" file.
  93.  *     [90/04/29            dlc]
  94.  * 
  95.  * Revision 1.15  90/04/18  19:51:27  dlc
  96.  *     Added the new routines local_file(), link_nofollow() for use in
  97.  *     dectecting whether a file is located in a local file system.  These
  98.  *     routines probably should have been in another module, but only
  99.  *     supfilesrv needs to do the check and none of its other modules seemed
  100.  *     appropriate.  Note, the implementation should be changed once we have
  101.  *     direct kernel support, for example the fstatfs(2) system call, for
  102.  *     detecting the type of file system a file resides.  Also, I changed
  103.  *     the routines which read the crosspatch crypt file or collection crypt
  104.  *     file to save the uid and gid from the stat information obtained via
  105.  *     the local_file() call (when the file is local) at the same time the
  106.  *     crypt key is read.  This change disallows non-local files for the
  107.  *     crypt key to plug a security hole involving the usage of the uid/gid
  108.  *     of the crypt file to define who the the file server should run as.  If
  109.  *     the saved uid/gid are both valid, then the server will set its uid/gid
  110.  *     to these values.
  111.  *     [90/04/18            dlc]
  112.  * 
  113.  * Revision 1.14  89/08/23  14:56:15  gm0w
  114.  *     Changed msgf routines to msg routines.
  115.  *     [89/08/23            gm0w]
  116.  * 
  117.  * Revision 1.13  89/08/03  19:57:33  mja
  118.  *     Remove setaid() call.
  119.  * 
  120.  * Revision 1.12  89/08/03  19:49:24  mja
  121.  *     Updated to use v*printf() in place of _doprnt().
  122.  *     [89/04/19            mja]
  123.  * 
  124.  * 11-Sep-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  125.  *    Added code to record release name in logfile.
  126.  *
  127.  * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  128.  *    Added host=<hostfile> support to releases file. [V7.12]
  129.  *
  130.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  131.  *    Added crosspatch support.  Created docrypt() routine for crypt
  132.  *    test message.
  133.  *
  134.  * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  135.  *    Removed common information logging code, the quiet switch, and
  136.  *    moved samehost() check to after device/inode check.
  137.  *
  138.  * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  139.  *    Added code for "release" support. [V5.11]
  140.  *
  141.  * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
  142.  *    Added code to record final status of client in logfile. [V5.10]
  143.  *
  144.  * 22-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
  145.  *    Mergered divergent CS and ECE versions. [V5.9a]
  146.  *
  147.  * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  148.  *    Removed support for version 3 of SUP protocol.  Added changes
  149.  *    to make lint happy.  Added calls to new logging routines. [V5.9]
  150.  *
  151.  * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
  152.  *    Fixed so no password check is done when crypts are used.
  153.  *
  154.  * 25-Nov-86  Rudy Nedved (ern) at Carnegie-Mellon University
  155.  *    Set F_APPEND fcntl in logging to increase the chance
  156.  *    that the log entry from this incarnation of the file
  157.  *    server will not be lost by another incarnation. [V5.8]
  158.  *
  159.  * 20-Oct-86  Dan Nydick (dan) at Carnegie-Mellon University
  160.  *    Changed not to call okmumbles when not compiled with CMUCS.
  161.  *
  162.  * 04-Aug-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  163.  *    Added code to increment scmdebug as more -N flags are
  164.  *    added. [V5.7]
  165.  *
  166.  * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  167.  *    Renamed local variable in main program from "sigmask" to
  168.  *    "signalmask" to avoid name conflict with 4.3BSD identifier.
  169.  *    Conditionally compile in calls to CMU routines, "setaid" and
  170.  *    "logaccess". [V5.6]
  171.  *
  172.  * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  173.  *    Changed supfilesrv to use the crypt file owner and group for
  174.  *    access purposes, rather than the directory containing the crypt
  175.  *    file. [V5.5]
  176.  *
  177.  * 07-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  178.  *    Added code to keep logfiles in repository collection directory.
  179.  *    Added code for locking collections. [V5.4]
  180.  *
  181.  * 05-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  182.  *    Added code to support new FSETUPBUSY return.  Now accepts all
  183.  *    connections and tells any clients after the 8th that the
  184.  *    fileserver is busy.  New clients will retry again later. [V5.3]
  185.  *
  186.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  187.  *    Major rewrite for protocol version 4. [V4.2]
  188.  *
  189.  * 12-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  190.  *    Fixed close of crypt file to use file pointer as argument
  191.  *    instead of string pointer.
  192.  *
  193.  * 24-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  194.  *    Allow "!hostname" lines and comments in collection "host" file.
  195.  *
  196.  * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  197.  *    Don't use access() on symbolic links since they may not point to
  198.  *    an existing file.
  199.  *
  200.  * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  201.  *    Added code to restrict file server availability to when it has
  202.  *    less than or equal to eight children.
  203.  *
  204.  * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  205.  *    Merged 4.1 and 4.2 versions together.
  206.  *
  207.  * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  208.  *    Created for 4.2 BSD.
  209.  *
  210.  **********************************************************************
  211.  */
  212.  
  213. #include <libc.h>
  214. #ifdef AFS
  215. #include <afs/param.h>
  216. #undef MAXNAMLEN
  217. #endif
  218. #include <sys/param.h>
  219. #include <c.h>
  220. #include <signal.h>
  221. #include <errno.h>
  222. #include <setjmp.h>
  223. #include <pwd.h>
  224. #include <grp.h>
  225. #if __STDC__
  226. #include <stdarg.h>
  227. #else
  228. #include <varargs.h>
  229. #endif
  230. #include <sys/time.h>
  231. #include <sys/resource.h>
  232. #include <sys/wait.h>
  233. #include <sys/stat.h>
  234. #include <sys/file.h>
  235. #include <sys/dir.h>
  236. #if    MACH
  237. #include <sys/ioctl.h>
  238. #endif
  239. #if    CMUCS
  240. #include <acc.h>
  241. #include <sys/ttyloc.h>
  242. #include <access.h>
  243. #include <sys/viceioctl.h>
  244. #else    CMUCS
  245. #define ACCESS_CODE_OK        0
  246. #define ACCESS_CODE_BADPASSWORD (-2)
  247. #endif  CMUCS
  248. #include "sup.h"
  249. #define MSGFILE
  250. #include "supmsg.h"
  251.  
  252. #ifdef    lint
  253. /*VARARGS1*//*ARGSUSED*/
  254. static void quit(status) {};
  255. #endif    /* lint */
  256.  
  257. extern int errno;
  258. long time ();
  259. uid_t getuid ();
  260.  
  261. int maxchildren;
  262.  
  263. /*
  264.  * These are used to save the stat information from the crosspatch crypt
  265.  * file or collection crypt file at the time it is opened for the crypt
  266.  * key and it is verified to be a local file.
  267.  */
  268. int runas_uid = -1;
  269. int runas_gid = -1;
  270.  
  271. #define PGMVERSION 13
  272.  
  273. /*************************
  274.  ***    M A C R O S    ***
  275.  *************************/
  276.  
  277. #define HASHBITS 8
  278. #define HASHSIZE (1<<HASHBITS)
  279. #define HASHMASK (HASHSIZE-1)
  280. #define HASHFUNC(x,y) ((x)&HASHMASK)
  281.  
  282. /*******************************************
  283.  ***    D A T A   S T R U C T U R E S    ***
  284.  *******************************************/
  285.  
  286. struct hashstruct {            /* hash table for number lists */
  287.     int Hnum1;            /* numeric keys */
  288.     int Hnum2;
  289.     char *Hname;            /* string value */
  290.     TREE *Htree;            /* TREE value */
  291.     struct hashstruct *Hnext;
  292. };
  293. typedef struct hashstruct HASH;
  294.  
  295. /*********************************************
  296.  ***    G L O B A L   V A R I A B L E S    ***
  297.  *********************************************/
  298.  
  299. char program[] = "supfilesrv";        /* program name for SCM messages */
  300. int progpid = -1;            /* and process id */
  301.  
  302. jmp_buf sjbuf;                /* jump location for network errors */
  303. TREELIST *listTL;            /* list of trees to upgrade */
  304.  
  305. int live;                /* -l flag */
  306. int dbgportsq;                /* -P flag */
  307. extern int scmdebug;            /* -N flag */
  308. extern int netfile;
  309. #ifdef RCS
  310. int candorcs;                /* -R flag */
  311. int dorcs = FALSE;
  312. #endif
  313.  
  314. char *clienthost;            /* host name of client */
  315. int nchildren;                /* number of children that exist */
  316. char *prefix;                /* collection pathname prefix */
  317. char *release;                /* collection release name */
  318. char *cryptkey;                /* encryption key if non-null */
  319. #ifdef CVS
  320. char *cvs_root;                /* RCS root */
  321. #endif
  322. char *rcs_branch;            /* RCS branch name */
  323. int lockfd;                /* descriptor of lock file */
  324.  
  325. /* global variables for scan functions */
  326. int trace = FALSE;            /* directory scan trace */
  327. int cancompress = FALSE;        /* Can we compress files */
  328. int docompress = FALSE;            /* Do we compress files */
  329.  
  330. HASH *uidH[HASHSIZE];            /* for uid and gid lookup */
  331. HASH *gidH[HASHSIZE];
  332. HASH *inodeH[HASHSIZE];            /* for inode lookup for linked file check */
  333.  
  334. char *fmttime ();            /* time format routine */
  335.  
  336. /*************************************
  337.  ***    M A I N   R O U T I N E    ***
  338.  *************************************/
  339.  
  340. main (argc,argv)
  341. int argc;
  342. char **argv;
  343. {
  344. #ifdef _ABI_SOURCE
  345.     register int x,pid;
  346.     sigset_t signalmask, oldsignalmask;
  347.     struct sigaction chldvec,ignvec,oldvec;
  348. #else
  349.     register int x,pid,signalmask;
  350.     struct sigvec chldvec,ignvec,oldvec;
  351. #endif
  352.     int chldsig ();
  353.     long tloc;
  354.  
  355.     /* initialize global variables */
  356.     pgmversion = PGMVERSION;    /* export version number */
  357.     server = TRUE;            /* export that we're not a server */
  358.     collname = NULL;        /* no current collection yet */
  359.     maxchildren = MAXCHILDREN;    /* defined in sup.h */
  360.  
  361.     init (argc,argv);        /* process arguments */
  362.  
  363. #ifdef HAS_DAEMON
  364.     if (!live)            /* if not debugging, turn into daemon */
  365.         daemon(0, 0);
  366. #endif
  367.  
  368.     logopen ("supfile");
  369.     tloc = time ((long *)NULL);
  370.     loginfo ("SUP File Server Version %d.%d (%s) starting at %s",
  371.         PROTOVERSION,PGMVERSION,scmversion,fmttime (tloc));
  372.     if (live) {
  373.         x = service ();
  374.         if (x != SCMOK)
  375.             logquit (1,"Can't connect to network");
  376.         answer ();
  377.         (void) serviceend ();
  378.         exit (0);
  379.     }
  380. #ifdef _ABI_SOURCE
  381.     ignvec.sa_handler = SIG_IGN;
  382.     sigemptyset (&(ignvec.sa_mask));
  383.     ignvec.sa_flags = 0;
  384.     (void) sigaction (SIGHUP,&ignvec,&oldvec);
  385.     (void) sigaction (SIGINT,&ignvec,&oldvec);
  386.     (void) sigaction (SIGPIPE,&ignvec,&oldvec);
  387.     chldvec.sa_handler = chldsig;
  388.     sigemptyset (&(chldvec.sa_mask));
  389.     chldvec.sa_flags = 0;
  390.     (void) sigaction (SIGCHLD,&chldvec,&oldvec);
  391. #else
  392.     ignvec.sv_handler = SIG_IGN;
  393.     ignvec.sv_onstack = 0;
  394.     ignvec.sv_mask = 0;
  395.     (void) sigvec (SIGHUP,&ignvec,&oldvec);
  396.     (void) sigvec (SIGINT,&ignvec,&oldvec);
  397.     (void) sigvec (SIGPIPE,&ignvec,&oldvec);
  398.     chldvec.sv_handler = chldsig;
  399.     chldvec.sv_mask = 0;
  400.     chldvec.sv_onstack = 0;
  401.     (void) sigvec (SIGCHLD,&chldvec,&oldvec);
  402. #endif
  403.     nchildren = 0;
  404.     for (;;) {
  405.         x = service ();
  406.         if (x != SCMOK) {
  407.             logerr ("Error in establishing network connection");
  408.             (void) servicekill ();
  409.             continue;
  410.         }
  411. #ifdef _ABI_SOURCE
  412.         sigemptyset (&signalmask);
  413.         sigaddset (&signalmask, SIGCHLD);
  414.         (void) sigprocmask (SIG_BLOCK, &signalmask, &oldsignalmask);
  415. #else
  416.         signalmask = sigblock(sigmask(SIGCHLD));
  417. #endif
  418.         if ((pid = fork()) == 0) { /* server process */
  419.             (void) serviceprep ();
  420.             answer ();
  421.             (void) serviceend ();
  422.             exit (0);
  423.         }
  424.         (void) servicekill ();    /* parent */
  425.         if (pid > 0) nchildren++;
  426. #ifdef _ABI_SOURCE
  427.         (void) sigprocmask (SIG_SETMASK, &oldsignalmask, NULL);
  428. #else
  429.         (void) sigsetmask(signalmask);
  430. #endif
  431.     }
  432. }
  433.  
  434. /*
  435.  * Child status signal handler
  436.  */
  437.  
  438. chldsig()
  439. {
  440.     union wait w;
  441.  
  442.     while (wait3(&w, WNOHANG, (struct rusage *)0) > 0) {
  443.         if (nchildren) nchildren--;
  444.     }
  445. }
  446.  
  447. /*****************************************
  448.  ***    I N I T I A L I Z A T I O N    ***
  449.  *****************************************/
  450.  
  451. usage ()
  452. {
  453.     quit (1,"Usage: supfilesrv [ -l | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
  454. }
  455.  
  456. init (argc,argv)
  457. int argc;
  458. char **argv;
  459. {
  460.     register int i;
  461.     register int x;
  462.     char *clienthost,*clientuser;
  463.     char *p,*q;
  464.     char buf[STRINGLENGTH];
  465.     int maxsleep;
  466.     register FILE *f;
  467.  
  468. #ifdef RCS
  469.         candorcs = FALSE;
  470. #endif
  471.     live = FALSE;
  472.     dbgportsq = FALSE;
  473.     scmdebug = 0;
  474.     clienthost = NULL;
  475.     clientuser = NULL;
  476.     maxsleep = 5;
  477.     if (--argc < 0)
  478.         usage ();
  479.     argv++;
  480.     while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
  481.         switch (argv[0][1]) {
  482.         case 'l':
  483.             live = TRUE;
  484.             break;
  485.         case 'P':
  486.             dbgportsq = TRUE;
  487.             break;
  488.         case 'N':
  489.             scmdebug++;
  490.             break;
  491.         case 'C':
  492.             if (--argc < 1)
  493.                 quit (1,"Missing arg to -C\n");
  494.             argv++;
  495.             maxchildren = atoi(argv[0]);
  496.             break;
  497.         case 'H':
  498.             if (--argc < 3)
  499.                 quit (1,"Missing args to -H\n");
  500.             argv++;
  501.             clienthost = argv[0];
  502.             clientuser = argv[1];
  503.             cryptkey = argv[2];
  504.             argc -= 2;
  505.             argv += 2;
  506.             break;
  507. #ifdef RCS
  508.                 case 'R':
  509.                         candorcs = TRUE;
  510.                         break;
  511. #endif
  512.         default:
  513.             fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
  514.             break;
  515.         }
  516.         --argc;
  517.         argv++;
  518.     }
  519.     if (clienthost == NULL) {
  520.         if (argc != 0)
  521.             usage ();
  522.         x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
  523.         if (x != SCMOK)
  524.             quit (1,"Error in network setup");
  525.         for (i = 0; i < HASHSIZE; i++)
  526.             uidH[i] = gidH[i] = inodeH[i] = NULL;
  527.         return;
  528.     }
  529.     server = FALSE;
  530.     if (argc < 1)
  531.         usage ();
  532.     f = fopen (cryptkey,"r");
  533.     if (f == NULL)
  534.         quit (1,"Unable to open cryptfile %s\n",cryptkey);
  535.     if (p = fgets (buf,STRINGLENGTH,f)) {
  536.         if (q = index (p,'\n'))  *q = '\0';
  537.         if (*p == '\0')
  538.             quit (1,"No cryptkey found in %s\n",cryptkey);
  539.         cryptkey = salloc (buf);
  540.     }
  541.     (void) fclose (f);
  542.     x = request (dbgportsq ? DEBUGFPORT : FILEPORT,clienthost,&maxsleep);
  543.     if (x != SCMOK)
  544.         quit (1,"Unable to connect to host %s\n",clienthost);
  545.     x = msgsignon ();
  546.     if (x != SCMOK)
  547.         quit (1,"Error sending signon request to fileserver\n");
  548.     x = msgsignonack ();
  549.     if (x != SCMOK)
  550.         quit (1,"Error reading signon reply from fileserver\n");
  551.     printf ("SUP Fileserver %d.%d (%s) %d on %s\n",
  552.         protver,pgmver,scmver,fspid,remotehost());
  553.     free (scmver);
  554.     scmver = NULL;
  555.     if (protver < 7)
  556.         quit (1,"Remote fileserver does not implement reverse sup\n");
  557.     xpatch = TRUE;
  558.     xuser = clientuser;
  559.     x = msgsetup ();
  560.     if (x != SCMOK)
  561.         quit (1,"Error sending setup request to fileserver\n");
  562.     x = msgsetupack ();
  563.     if (x != SCMOK)
  564.         quit (1,"Error reading setup reply from fileserver\n");
  565.     switch (setupack) {
  566.     case FSETUPOK:
  567.         break;
  568.     case FSETUPSAME:
  569.         quit (1,"User %s not found on remote client\n",xuser);
  570.     case FSETUPHOST:
  571.         quit (1,"This host has no permission to reverse sup\n");
  572.     default:
  573.         quit (1,"Unrecognized file server setup status %d\n",setupack);
  574.     }
  575.     if (netcrypt (cryptkey) != SCMOK )
  576.         quit (1,"Running non-crypting fileserver\n");
  577.     crypttest = CRYPTTEST;
  578.     x = msgcrypt ();
  579.     if (x != SCMOK)
  580.         quit (1,"Error sending encryption test request\n");
  581.     x = msgcryptok ();
  582.     if (x == SCMEOF)
  583.         quit (1,"Data encryption test failed\n");
  584.     if (x != SCMOK)
  585.         quit (1,"Error reading encryption test reply\n");
  586.     logcrypt = CRYPTTEST;
  587.     loguser = NULL;
  588.     logpswd = NULL;
  589.     if (netcrypt (PSWDCRYPT) != SCMOK)    /* encrypt password data */
  590.         quit (1,"Running non-crypting fileserver\n");
  591.     x = msglogin ();
  592.     (void) netcrypt ((char *)NULL);    /* turn off encryption */
  593.     if (x != SCMOK)
  594.         quit (1,"Error sending login request to file server\n");
  595.     x = msglogack ();
  596.     if (x != SCMOK)
  597.         quit (1,"Error reading login reply from file server\n");
  598.     if (logack == FLOGNG)
  599.         quit (1,"%s\nImproper login to %s account\n",logerror,xuser);
  600.     xargc = argc;
  601.     xargv = argv;
  602.     x = msgxpatch ();
  603.     if (x != SCMOK)
  604.         quit (1,"Error sending crosspatch request\n");
  605.         crosspatch ();
  606.     exit (0);
  607. }
  608.  
  609. /*****************************************
  610.  ***    A N S W E R   R E Q U E S T    ***
  611.  *****************************************/
  612.  
  613. answer ()
  614. {
  615.     long starttime;
  616.     register int x;
  617.  
  618.     progpid = fspid = getpid ();
  619.     collname = NULL;
  620.     basedir = NULL;
  621.     prefix = NULL;
  622.     release = NULL;
  623.         rcs_branch = NULL;
  624. #ifdef CVS
  625.         cvs_root = NULL;
  626. #endif
  627.     goawayreason = NULL;
  628.     donereason = NULL;
  629.     lockfd = -1;
  630.     starttime = time ((long *)NULL);
  631.     if (!setjmp (sjbuf)) {
  632.         signon ();
  633.         setup ();
  634.         docrypt ();
  635.         login ();
  636.         if (xpatch) {
  637.             int fd;
  638.  
  639.             x = msgxpatch ();
  640.             if (x != SCMOK)
  641.                 exit (0);
  642.             xargv[0] = "sup";
  643.             xargv[1] = "-X";
  644.             xargv[xargc] = (char *)NULL;
  645.             (void) dup2 (netfile,0);
  646.             (void) dup2 (netfile,1);
  647.             (void) dup2 (netfile,2);
  648.             fd = getdtablesize ();
  649.             while (--fd > 2)
  650.                 (void) close (fd);
  651.             execvp (xargv[0],xargv);
  652.             exit (0);
  653.         }
  654.         listfiles ();
  655.         sendfiles ();
  656.     }
  657.     finishup (starttime);
  658.     if (collname)  free (collname);
  659.     if (basedir)  free (basedir);
  660.     if (prefix)  free (prefix);
  661.     if (release)  free (release);
  662.     if (rcs_branch)  free (rcs_branch);
  663. #ifdef CVS
  664.     if (cvs_root)  free (cvs_root);
  665. #endif
  666.     if (goawayreason) {
  667.         if (donereason == goawayreason)
  668.             donereason = NULL;
  669.         free (goawayreason);
  670.     }
  671.     if (donereason)  free (donereason);
  672.     if (lockfd >= 0)  (void) close (lockfd);
  673.     endpwent ();
  674.     (void) endgrent ();
  675. #if    CMUCS
  676.     endacent ();
  677. #endif    /* CMUCS */
  678.     Hfree (uidH);
  679.     Hfree (gidH);
  680.     Hfree (inodeH);
  681. }
  682.  
  683. /*****************************************
  684.  ***    S I G N   O N   C L I E N T    ***
  685.  *****************************************/
  686.  
  687. signon ()
  688. {
  689.     register int x;
  690.  
  691.     xpatch = FALSE;
  692.     x = msgsignon ();
  693.     if (x != SCMOK)  goaway ("Error reading signon request from client");
  694.     x = msgsignonack ();
  695.     if (x != SCMOK)  goaway ("Error sending signon reply to client");
  696.     free (scmver);
  697.     scmver = NULL;
  698. }
  699.  
  700. /*****************************************************************
  701.  ***    E X C H A N G E   S E T U P   I N F O R M A T I O N    ***
  702.  *****************************************************************/
  703.  
  704. setup ()
  705. {
  706.     register int x;
  707.     char *p,*q;
  708.     char buf[STRINGLENGTH];
  709.     register FILE *f;
  710.     struct stat sbuf;
  711.     register TREELIST *tl;
  712.  
  713.     if (protver > 7) {
  714.         cancompress = TRUE;
  715.     }
  716.     x = msgsetup ();
  717.     if (x != SCMOK)  goaway ("Error reading setup request from client");
  718.     if (protver < 4) {
  719.         setupack = FSETUPOLD;
  720.         (void) msgsetupack ();
  721.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  722.         goaway ("Sup client using obsolete version of protocol");
  723.     }
  724.     if (xpatch) {
  725.         register struct passwd *pw;
  726.         extern int link_nofollow(), local_file();
  727.  
  728.         if ((pw = getpwnam (xuser)) == NULL) {
  729.             setupack = FSETUPSAME;
  730.             (void) msgsetupack ();
  731.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  732.             goaway ("User not found");
  733.         }
  734.         (void) free (xuser);
  735.         xuser = salloc (pw->pw_dir);
  736.  
  737.         /* check crosspatch host access file */
  738.         cryptkey = NULL;
  739.         (void) sprintf (buf,FILEXPATCH,xuser);
  740.  
  741.         /* Turn off link following */
  742.         if (link_nofollow(1) != -1) {
  743.             int hostok = FALSE;
  744.             /* get stat info before open */
  745.             if (stat(buf, &sbuf) == -1)
  746.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  747.  
  748.             if ((f = fopen (buf,"r")) != NULL) {
  749.                 struct stat fsbuf;
  750.  
  751.                 while (p = fgets (buf,STRINGLENGTH,f)) {
  752.                     q = index (p,'\n');
  753.                     if (q)  *q = 0;
  754.                     if (index ("#;:",*p))  continue;
  755.                     q = nxtarg (&p," \t");
  756.                     if (*p == '\0')  continue;
  757.                     if (!matchhost(q)) continue;
  758.  
  759.                     cryptkey = salloc (p);
  760.                     hostok = TRUE;
  761.                     if (local_file(fileno(f), &fsbuf) > 0
  762.                         && stat_info_ok(&sbuf, &fsbuf)) {
  763.                         runas_uid = sbuf.st_uid;
  764.                         runas_gid = sbuf.st_gid;
  765.                     }
  766.                     break;
  767.                 }
  768.                 (void) fclose (f);
  769.             }
  770.  
  771.             /* Restore link following */
  772.             if (link_nofollow(0) == -1)
  773.                 goaway ("Restore link following");
  774.  
  775.             if (!hostok) {
  776.                 setupack = FSETUPHOST;
  777.                 (void) msgsetupack ();
  778.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  779.                 goaway ("Host not on access list");
  780.             }
  781.         }
  782.         setupack = FSETUPOK;
  783.         x = msgsetupack ();
  784.         if (x != SCMOK)
  785.             goaway ("Error sending setup reply to client");
  786.         return;
  787.     }
  788. #ifdef RCS
  789.         if (candorcs && release != NULL &&
  790.             (strncmp(release, "RCS.", 4) == 0)) {
  791.                 rcs_branch = salloc(&release[4]);
  792.                 free(release);
  793.                 release = salloc("RCS");
  794.                 dorcs = TRUE;
  795.         }
  796. #endif
  797.     if (release == NULL)
  798.         release = salloc (DEFRELEASE);
  799.     if (basedir == NULL || *basedir == '\0') {
  800.         basedir = NULL;
  801.         (void) sprintf (buf,FILEDIRS,DEFDIR);
  802.         f = fopen (buf,"r");
  803.         if (f) {
  804.             while (p = fgets (buf,STRINGLENGTH,f)) {
  805.                 q = index (p,'\n');
  806.                 if (q)  *q = 0;
  807.                 if (index ("#;:",*p))  continue;
  808.                 q = nxtarg (&p," \t=");
  809.                 if (strcmp(q,collname) == 0) {
  810.                     basedir = skipover(p," \t=");
  811.                     basedir = salloc (basedir);
  812.                     break;
  813.                 }
  814.             }
  815.             (void) fclose (f);
  816.         }
  817.         if (basedir == NULL) {
  818.             (void) sprintf (buf,FILEBASEDEFAULT,collname);
  819.             basedir = salloc(buf);
  820.         }
  821.     }
  822.     if (chdir (basedir) < 0)
  823.         goaway ("Can't chdir to base directory %s",basedir);
  824.     (void) sprintf (buf,FILEPREFIX,collname);
  825.     f = fopen (buf,"r");
  826.     if (f) {
  827.         while (p = fgets (buf,STRINGLENGTH,f)) {
  828.             q = index (p,'\n');
  829.             if (q)  *q = 0;
  830.             if (index ("#;:",*p))  continue;
  831.             prefix = salloc(p);
  832.             if (chdir (prefix) < 0)
  833.                 goaway ("Can't chdir to %s from base directory %s",
  834.                     prefix,basedir);
  835.             break;
  836.         }
  837.         (void) fclose (f);
  838.     }
  839.     x = stat (".",&sbuf);
  840.     if (prefix)  (void) chdir (basedir);
  841.     if (x < 0)
  842.         goaway ("Can't stat base/prefix directory");
  843.     if (nchildren >= maxchildren) {
  844.         setupack = FSETUPBUSY;
  845.         (void) msgsetupack ();
  846.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  847.         goaway ("Sup client told to try again later");
  848.     }
  849.     if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
  850.         setupack = FSETUPSAME;
  851.         (void) msgsetupack ();
  852.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  853.         goaway ("Attempt to upgrade to same directory on same host");
  854.     }
  855.     /* obtain release information */
  856.     if (!getrelease (release)) {
  857.         setupack = FSETUPRELEASE;
  858.         (void) msgsetupack ();
  859.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  860.         goaway ("Invalid release information");
  861.     }
  862.     /* check host access file */
  863.     cryptkey = NULL;
  864.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  865.         char *h;
  866.         if ((h = tl->TLhost) == NULL)
  867.             h = FILEHOSTDEF;
  868.         (void) sprintf (buf,FILEHOST,collname,h);
  869.         f = fopen (buf,"r");
  870.         if (f) {
  871.             int hostok = FALSE;
  872.             while (p = fgets (buf,STRINGLENGTH,f)) {
  873.                 int not;
  874.                 q = index (p,'\n');
  875.                 if (q)  *q = 0;
  876.                 if (index ("#;:",*p))  continue;
  877.                 q = nxtarg (&p," \t");
  878.                 if ((not = (*q == '!')) && *++q == '\0')
  879.                     q = nxtarg (&p," \t");
  880.                 hostok = (not == (matchhost(q) == 0));
  881.                 if (hostok) {
  882.                     while ((*p == ' ') || (*p == '\t')) p++;
  883.                     if (*p)  cryptkey = salloc (p);
  884.                     break;
  885.                 }
  886.             }
  887.             (void) fclose (f);
  888.             if (!hostok) {
  889.                 setupack = FSETUPHOST;
  890.                 (void) msgsetupack ();
  891.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  892.                 goaway ("Host not on access list for %s",
  893.                     collname);
  894.             }
  895.         }
  896.     }
  897.     /* try to lock collection */
  898.     (void) sprintf (buf,FILELOCK,collname);
  899.     x = open (buf,O_RDONLY,0);
  900.     if (x >= 0) {
  901.         if (flock (x,(LOCK_SH|LOCK_NB)) < 0) {
  902.             (void) close (x);
  903.             if (errno != EWOULDBLOCK)
  904.                 goaway ("Can't lock collection %s",collname);
  905.             setupack = FSETUPBUSY;
  906.             (void) msgsetupack ();
  907.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  908.             goaway ("Sup client told to wait for lock");
  909.         }
  910.         lockfd = x;
  911.     }
  912.     setupack = FSETUPOK;
  913.     x = msgsetupack ();
  914.     if (x != SCMOK)  goaway ("Error sending setup reply to client");
  915. }
  916.  
  917. /** Test data encryption **/
  918. docrypt ()
  919. {
  920.     register int x;
  921.     char *p,*q;
  922.     char buf[STRINGLENGTH];
  923.     register FILE *f;
  924.     struct stat sbuf;
  925.     extern int  link_nofollow(), local_file();
  926.  
  927.     if (!xpatch) {
  928.         (void) sprintf (buf,FILECRYPT,collname);
  929.  
  930.         /* Turn off link following */
  931.         if (link_nofollow(1) != -1) {
  932.             /* get stat info before open */
  933.             if (stat(buf, &sbuf) == -1)
  934.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  935.  
  936.             if ((f = fopen (buf,"r")) != NULL) {
  937.                 struct stat fsbuf;
  938.  
  939.                 if (cryptkey == NULL &&
  940.                     (p = fgets (buf,STRINGLENGTH,f))) {
  941.                     if (q = index (p,'\n'))  *q = '\0';
  942.                     if (*p)  cryptkey = salloc (buf);
  943.                 }
  944.                 if (local_file(fileno(f), &fsbuf) > 0
  945.                     && stat_info_ok(&sbuf, &fsbuf)) {
  946.                     runas_uid = sbuf.st_uid;
  947.                     runas_gid = sbuf.st_gid;
  948.                 }
  949.                 (void) fclose (f);
  950.             }
  951.             /* Restore link following */
  952.             if (link_nofollow(0) == -1)
  953.                 goaway ("Restore link following");
  954.         }
  955.     }
  956.     if ( netcrypt (cryptkey) != SCMOK )
  957.         goaway ("Runing non-crypting supfilesrv");
  958.     x = msgcrypt ();
  959.     if (x != SCMOK)
  960.         goaway ("Error reading encryption test request from client");
  961.     (void) netcrypt ((char *)NULL);
  962.     if (strcmp(crypttest,CRYPTTEST) != 0)
  963.         goaway ("Client not encrypting data properly");
  964.     free (crypttest);
  965.     crypttest = NULL;
  966.     x = msgcryptok ();
  967.     if (x != SCMOK)
  968.         goaway ("Error sending encryption test reply to client");
  969. }
  970.  
  971. /***************************************************************
  972.  ***    C O N N E C T   T O   P R O P E R   A C C O U N T    ***
  973.  ***************************************************************/
  974.  
  975. login ()
  976. {
  977.     char *changeuid ();
  978.     register int x,fileuid,filegid;
  979.  
  980.     (void) netcrypt (PSWDCRYPT);    /* encrypt acct name and password */
  981.     x = msglogin ();
  982.     (void) netcrypt ((char *)NULL); /* turn off encryption */
  983.     if (x != SCMOK)  goaway ("Error reading login request from client");
  984.     if ( logcrypt ) {
  985.         if (strcmp(logcrypt,CRYPTTEST) != 0) {
  986.         logack = FLOGNG;
  987.         logerror = "Improper login encryption";
  988.         (void) msglogack ();
  989.         goaway ("Client not encrypting login information properly");
  990.         }
  991.         free (logcrypt);
  992.         logcrypt = NULL;
  993.     }
  994.     if (loguser == NULL) {
  995.         if (cryptkey) {
  996.             if (runas_uid >= 0 && runas_gid >= 0) {
  997.                 fileuid = runas_uid;
  998.                 filegid = runas_gid;
  999.                 loguser = NULL;
  1000.             } else
  1001.                 loguser = salloc (DEFUSER);
  1002.         } else
  1003.             loguser = salloc (DEFUSER);
  1004.     }
  1005.     if ((logerror = changeuid (loguser,logpswd,fileuid,filegid)) != NULL) {
  1006.         logack = FLOGNG;
  1007.         (void) msglogack ();
  1008.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  1009.         goaway ("Client denied login access");
  1010.     }
  1011.     if (loguser)  free (loguser);
  1012.     if (logpswd)  free (logpswd);
  1013.     logack = FLOGOK;
  1014.     x = msglogack ();
  1015.     if (x != SCMOK)  goaway ("Error sending login reply to client");
  1016.     if (!xpatch)  /* restore desired encryption */
  1017.         if (netcrypt (cryptkey) != SCMOK)
  1018.             goaway("Running non-crypting supfilesrv");
  1019.     free (cryptkey);
  1020.     cryptkey = NULL;
  1021. }
  1022.  
  1023. /*****************************************
  1024.  ***    M A K E   N A M E   L I S T    ***
  1025.  *****************************************/
  1026.  
  1027. listfiles ()
  1028. {
  1029.     int denyone();
  1030.     register int x;
  1031.  
  1032.     refuseT = NULL;
  1033.     x = msgrefuse ();
  1034.     if (x != SCMOK)  goaway ("Error reading refuse list from client");
  1035.     getscanlists ();
  1036.     Tfree (&refuseT);
  1037.     x = msglist ();
  1038.     if (x != SCMOK)  goaway ("Error sending file list to client");
  1039.     Tfree (&listT);
  1040.     listT = NULL;
  1041.     needT = NULL;
  1042.     x = msgneed ();
  1043.     if (x != SCMOK)
  1044.         goaway ("Error reading needed files list from client");
  1045.     denyT = NULL;
  1046.     (void) Tprocess (needT,denyone);
  1047.     Tfree (&needT);
  1048.     x = msgdeny ();
  1049.     if (x != SCMOK)  goaway ("Error sending denied files list to client");
  1050.     Tfree (&denyT);
  1051. }
  1052.  
  1053. denyone (t)
  1054. register TREE *t;
  1055. {
  1056.     register TREELIST *tl;
  1057.     register char *name = t->Tname;
  1058.     register int update = (t->Tflags&FUPDATE) != 0;
  1059.     struct stat sbuf;
  1060.     register TREE *tlink;
  1061.     TREE *linkcheck ();
  1062.     char slinkname[STRINGLENGTH];
  1063.     register int x;
  1064.  
  1065.     for (tl = listTL; tl != NULL; tl = tl->TLnext)
  1066.         if ((t = Tsearch (tl->TLtree,name)) != NULL)
  1067.             break;
  1068.     if (t == NULL) {
  1069.         (void) Tinsert (&denyT,name,FALSE);
  1070.         return (SCMOK);
  1071.     }
  1072.     cdprefix (tl->TLprefix);
  1073.     if ((t->Tmode&S_IFMT) == S_IFLNK)
  1074.         x = lstat(name,&sbuf);
  1075.     else
  1076.         x = stat(name,&sbuf);
  1077.     if (x < 0 || (sbuf.st_mode&S_IFMT) != (t->Tmode&S_IFMT)) {
  1078.         (void) Tinsert (&denyT,name,FALSE);
  1079.         return (SCMOK);
  1080.     }
  1081.     switch (t->Tmode&S_IFMT) {
  1082.     case S_IFLNK:
  1083.         if ((x = readlink (name,slinkname,STRINGLENGTH)) <= 0) {
  1084.             (void) Tinsert (&denyT,name,FALSE);
  1085.             return (SCMOK);
  1086.         }
  1087.         slinkname[x] = '\0';
  1088.         (void) Tinsert (&t->Tlink,slinkname,FALSE);
  1089.         break;
  1090.     case S_IFREG:
  1091.         if (sbuf.st_nlink > 1 &&
  1092.             (tlink = linkcheck (t,(int)sbuf.st_dev,(int)sbuf.st_ino)))
  1093.         {
  1094.             (void) Tinsert (&tlink->Tlink,name,FALSE);
  1095.             return (SCMOK);
  1096.         }
  1097.         if (update)  t->Tflags |= FUPDATE;
  1098.     case S_IFDIR:
  1099.         t->Tuid = sbuf.st_uid;
  1100.         t->Tgid = sbuf.st_gid;
  1101.         break;
  1102.     default:
  1103.         (void) Tinsert (&denyT,name,FALSE);
  1104.         return (SCMOK);
  1105.     }
  1106.     t->Tflags |= FNEEDED;
  1107.     return (SCMOK);
  1108. }
  1109.  
  1110. /*********************************
  1111.  ***    S E N D   F I L E S    ***
  1112.  *********************************/
  1113.  
  1114. sendfiles ()
  1115. {
  1116.     int sendone(),senddir(),sendfile();
  1117.     register TREELIST *tl;
  1118.     register int x;
  1119.  
  1120.     /* Does the protocol support compression */
  1121.     if (cancompress) {
  1122.         /* Check for compression on sending files */
  1123.         x = msgcompress();
  1124.         if ( x != SCMOK)
  1125.             goaway ("Error sending compression check to server");
  1126.     }
  1127.     /* send all files */
  1128.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1129.         cdprefix (tl->TLprefix);
  1130. #ifdef CVS
  1131.                 if (candorcs) {
  1132.                         cvs_root = getcwd(NULL, 256);
  1133.                         if (access("CVSROOT", F_OK) < 0)
  1134.                                 dorcs = FALSE;
  1135.                         else {
  1136.                                 loginfo("is a CVSROOT \"%s\"\n", cvs_root);
  1137.                                 dorcs = TRUE;
  1138.                         }
  1139.                 }
  1140. #endif
  1141.         (void) Tprocess (tl->TLtree,sendone);
  1142.     }
  1143.     /* send directories in reverse order */
  1144.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1145.         cdprefix (tl->TLprefix);
  1146.         (void) Trprocess (tl->TLtree,senddir);
  1147.     }
  1148.     x = msgsend ();
  1149.     if (x != SCMOK)
  1150.         goaway ("Error reading receive file request from client");
  1151.     upgradeT = NULL;
  1152.     x = msgrecv (sendfile,0);
  1153.     if (x != SCMOK)
  1154.         goaway ("Error sending file to client");
  1155. }
  1156.  
  1157. sendone (t)
  1158. TREE *t;
  1159. {
  1160.     register int x,fd;
  1161.     register int fdtmp;
  1162.     char sys_com[STRINGLENGTH], temp_file[STRINGLENGTH], rcs_file[STRINGLENGTH];
  1163.         union wait status;
  1164.     char *uconvert(),*gconvert();
  1165.     int sendfile ();
  1166.  
  1167.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1168.         return (SCMOK);
  1169.     if ((t->Tmode&S_IFMT) == S_IFDIR) /* send no directories this pass */
  1170.         return (SCMOK);
  1171.     x = msgsend ();
  1172.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1173.     upgradeT = t;            /* upgrade file pointer */
  1174.     fd = -1;            /* no open file */
  1175.     if ((t->Tmode&S_IFMT) == S_IFREG) {
  1176.         if (!listonly && (t->Tflags&FUPDATE) == 0) {
  1177. #ifdef RCS
  1178.                         if (dorcs) {
  1179.                                 char rcs_release[STRINGLENGTH];
  1180.  
  1181.                 tmpnam(rcs_file);
  1182.                                 if (strcmp(&t->Tname[strlen(t->Tname)-2], ",v") == 0) {
  1183.                                         t->Tname[strlen(t->Tname)-2] = '\0';
  1184.                                         if (rcs_branch != NULL)
  1185. #ifdef CVS
  1186.                                                 sprintf(rcs_release, "-r %s", rcs_branch);
  1187. #else
  1188.                                                 sprintf(rcs_release, "-r%s", rcs_branch);
  1189. #endif
  1190.                                         else
  1191.                                                 rcs_release[0] = '\0';
  1192. #ifdef CVS
  1193.                                         sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, t->Tname, rcs_file);
  1194. #else
  1195.                                         sprintf(sys_com, "co -q -p %s %s > %s 2> /dev/null\n", rcs_release, t->Tname, rcs_file);
  1196. #endif
  1197.                                         /*loginfo("using rcs mode \"%s\"\n", sys_com);*/
  1198.                                         status.w_status = system(sys_com);
  1199.                                         if (status.w_status < 0 || status.w_retcode) {
  1200.                                                 /* Just in case */
  1201.                                                 unlink(rcs_file);
  1202.                                                 if (status.w_status < 0) {
  1203.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1204.                                                         t->Tmode = 0;
  1205.                                                 }
  1206.                                                 else {
  1207.                                                         /*logerr("rcs command failed \"%s\" = %d\n",
  1208.                                                                sys_com, status.w_retcode);*/
  1209.                                                         t->Tflags |= FUPDATE;
  1210.                                                 }
  1211.                                         }
  1212.                                         else if (docompress) {
  1213.                                                 tmpnam(temp_file);
  1214.                                                 sprintf(sys_com, "gzip -c < %s > %s\n", rcs_file, temp_file);
  1215.                                                 if (system(sys_com) < 0) {
  1216.                                                         /* Just in case */
  1217.                                                         unlink(temp_file);
  1218.                                                         unlink(rcs_file);
  1219.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1220.                                                         t->Tmode = 0;
  1221.                                                 }
  1222.                                                 fd = open (temp_file,O_RDONLY,0);
  1223.                                         }
  1224.                                         else
  1225.                                                 fd = open (rcs_file,O_RDONLY,0);
  1226.                                 }
  1227.                         }
  1228. #endif
  1229.                         if (fd == -1) {
  1230.                                 if (docompress) {
  1231.                                         tmpnam(temp_file);
  1232.                                         sprintf(sys_com, "gzip -c < %s > %s\n", t->Tname, temp_file);
  1233.                                         if (system(sys_com) < 0) {
  1234.                                                 /* Just in case */
  1235.                                                 unlink(temp_file);
  1236.                                                 goaway ("We died trying to \"%s\"", sys_com);
  1237.                                                 t->Tmode = 0;
  1238.                                         }
  1239.                                         fd = open (temp_file,O_RDONLY,0);
  1240.                                 }
  1241.                                 else
  1242.                                         fd = open (t->Tname,O_RDONLY,0);
  1243.                         }
  1244.             if (fd < 0 && (t->Tflags&FUPDATE) == 0)  t->Tmode = 0;
  1245.         }
  1246.         if (t->Tmode) {
  1247.             t->Tuser = salloc (uconvert (t->Tuid));
  1248.             t->Tgroup = salloc (gconvert (t->Tgid));
  1249.         }
  1250.     }
  1251.     x = msgrecv (sendfile,fd);
  1252.     if (docompress)
  1253.         unlink(temp_file);
  1254. #ifdef RCS
  1255.     if (dorcs)
  1256.         unlink(rcs_file);
  1257. #endif
  1258.     if (x != SCMOK)  goaway ("Error sending file to client");
  1259.     return (SCMOK);
  1260. }
  1261.  
  1262. senddir (t)
  1263. TREE *t;
  1264. {
  1265.     register int x;
  1266.     char *uconvert(),*gconvert();
  1267.     int sendfile ();
  1268.  
  1269.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1270.         return (SCMOK);
  1271.     if ((t->Tmode&S_IFMT) != S_IFDIR) /* send only directories this pass */
  1272.         return (SCMOK);
  1273.     x = msgsend ();
  1274.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1275.     upgradeT = t;            /* upgrade file pointer */
  1276.     t->Tuser = salloc (uconvert (t->Tuid));
  1277.     t->Tgroup = salloc (gconvert (t->Tgid));
  1278.     x = msgrecv (sendfile,0);
  1279.     if (x != SCMOK)  goaway ("Error sending file to client");
  1280.     return (SCMOK);
  1281. }
  1282.  
  1283. sendfile (t,ap)
  1284. register TREE *t;
  1285. va_list ap;
  1286. {
  1287.     register int x;
  1288.     int fd = va_arg(ap,int);
  1289.     if ((t->Tmode&S_IFMT) != S_IFREG || listonly || (t->Tflags&FUPDATE))
  1290.         return (SCMOK);
  1291.     x = writefile (fd);
  1292.     if (x != SCMOK)  goaway ("Error sending file to client");
  1293.         (void) close (fd);
  1294.     return (SCMOK);
  1295. }
  1296.  
  1297. /*****************************************
  1298.  ***    E N D   C O N N E C T I O N    ***
  1299.  *****************************************/
  1300.  
  1301. finishup (starttime)
  1302. long starttime;
  1303. {
  1304.     register int x = SCMOK;
  1305.     char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
  1306.     int logfd;
  1307.     struct stat sbuf;
  1308.     long finishtime;
  1309.     char *releasename;
  1310.  
  1311.     (void) netcrypt ((char *)NULL);
  1312.     if (protver < 6) {
  1313.         if (goawayreason != NULL)
  1314.             free (goawayreason);
  1315.         goawayreason = (char *)NULL;
  1316.         x = msggoaway();
  1317.         doneack = FDONESUCCESS;
  1318.         donereason = salloc ("Unknown");
  1319.     } else if (goawayreason == (char *)NULL)
  1320.         x = msgdone ();
  1321.     else {
  1322.         doneack = FDONEGOAWAY;
  1323.         donereason = goawayreason;
  1324.     }
  1325.     if (x == SCMEOF || x == SCMERR) {
  1326.         doneack = FDONEUSRERROR;
  1327.         donereason = salloc ("Premature EOF on network");
  1328.     } else if (x != SCMOK) {
  1329.         doneack = FDONESRVERROR;
  1330.         donereason = salloc ("Unknown SCM code");
  1331.     }
  1332.     if (doneack == FDONEDONTLOG)
  1333.         return;
  1334.     if (donereason == NULL)
  1335.         donereason = salloc ("No reason");
  1336.     if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
  1337.         logerr ("%s", donereason);
  1338.     else if (doneack == FDONEGOAWAY)
  1339.         logerr ("GOAWAY: %s",donereason);
  1340.     else if (doneack != FDONESUCCESS)
  1341.         logerr ("Reason %d:  %s",doneack,donereason);
  1342.     goawayreason = donereason;
  1343.     cdprefix ((char *)NULL);
  1344.     (void) sprintf (lognam,FILELOGFILE,collname);
  1345.     if ((logfd = open(lognam,O_APPEND|O_WRONLY,0644)) < 0)
  1346.         return; /* can not open file up...error */
  1347.     finishtime = time ((long *)NULL);
  1348.     p = tmpbuf;
  1349.     (void) sprintf (p,"%s ",fmttime (lasttime));
  1350.     p += strlen(p);
  1351.     (void) sprintf (p,"%s ",fmttime (starttime));
  1352.     p += strlen(p);
  1353.     (void) sprintf (p,"%s ",fmttime (finishtime));
  1354.     p += strlen(p);
  1355.     if ((releasename = release) == NULL)
  1356.         releasename = "UNKNOWN";
  1357.     (void) sprintf (p,"%s %s %d %s\n",remotehost(),releasename,
  1358.         FDONESUCCESS-doneack,donereason);
  1359.     p += strlen(p);
  1360. #if    MACH
  1361.     /* if we are busy dont get stuck updating the disk if full */
  1362.     if(setupack == FSETUPBUSY) {
  1363.         long l = FIOCNOSPC_ERROR;
  1364.         ioctl(logfd, FIOCNOSPC, &l);
  1365.     }
  1366. #endif    /* MACH */
  1367.     (void) write(logfd,tmpbuf,(p - tmpbuf));
  1368.     (void) close(logfd);
  1369. }
  1370.  
  1371. /***************************************************
  1372.  ***    H A S H   T A B L E   R O U T I N E S    ***
  1373.  ***************************************************/
  1374.  
  1375. Hfree (table)
  1376. HASH **table;
  1377. {
  1378.     register HASH *h;
  1379.     register int i;
  1380.     for (i = 0; i < HASHSIZE; i++)
  1381.         while (h = table[i]) {
  1382.             table[i] = h->Hnext;
  1383.             if (h->Hname)  free (h->Hname);
  1384.             free ((char *)h);
  1385.         }
  1386. }
  1387.  
  1388. HASH *Hlookup (table,num1,num2)
  1389. HASH **table;
  1390. int num1,num2;
  1391. {
  1392.     register HASH *h;
  1393.     register int hno;
  1394.     hno = HASHFUNC(num1,num2);
  1395.     for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
  1396.     return (h);
  1397. }
  1398.  
  1399. Hinsert (table,num1,num2,name,tree)
  1400. HASH **table;
  1401. int num1,num2;
  1402. char *name;
  1403. TREE *tree;
  1404. {
  1405.     register HASH *h;
  1406.     register int hno;
  1407.     hno = HASHFUNC(num1,num2);
  1408.     h = (HASH *) malloc (sizeof(HASH));
  1409.     h->Hnum1 = num1;
  1410.     h->Hnum2 = num2;
  1411.     h->Hname = name;
  1412.     h->Htree = tree;
  1413.     h->Hnext = table[hno];
  1414.     table[hno] = h;
  1415. }
  1416.  
  1417. /*********************************************
  1418.  ***    U T I L I T Y   R O U T I N E S    ***
  1419.  *********************************************/
  1420.  
  1421. TREE *linkcheck (t,d,i)
  1422. TREE *t;
  1423. int d,i;            /* inode # and device # */
  1424. {
  1425.     register HASH *h;
  1426.     h = Hlookup (inodeH,i,d);
  1427.     if (h)  return (h->Htree);
  1428.     Hinsert (inodeH,i,d,(char *)NULL,t);
  1429.     return ((TREE *)NULL);
  1430. }
  1431.  
  1432. char *uconvert (uid)
  1433. int uid;
  1434. {
  1435.     register struct passwd *pw;
  1436.     register char *p;
  1437.     register HASH *u;
  1438.     u = Hlookup (uidH,uid,0);
  1439.     if (u)  return (u->Hname);
  1440.     pw = getpwuid (uid);
  1441.     if (pw == NULL)  return ("");
  1442.     p = salloc (pw->pw_name);
  1443.     Hinsert (uidH,uid,0,p,(TREE*)NULL);
  1444.     return (p);
  1445. }
  1446.  
  1447. char *gconvert (gid)
  1448. int gid;
  1449. {
  1450.     register struct group *gr;
  1451.     register char *p;
  1452.     register HASH *g;
  1453.     g = Hlookup (gidH,gid,0);
  1454.     if (g)  return (g->Hname);
  1455.     gr = getgrgid (gid);
  1456.     if (gr == NULL)  return ("");
  1457.     p = salloc (gr->gr_name);
  1458.     Hinsert (gidH,gid,0,p,(TREE *)NULL);
  1459.     return (p);
  1460. }
  1461.  
  1462. char *changeuid (namep,passwordp,fileuid,filegid)
  1463. char *namep,*passwordp;
  1464. int fileuid,filegid;
  1465. {
  1466.     char *okpassword ();
  1467.     char *group,*account,*pswdp;
  1468.     struct passwd *pwd;
  1469.     struct group *grp;
  1470. #if    CMUCS
  1471.     struct account *acc;
  1472.     struct ttyloc tlc;
  1473. #endif    /* CMUCS */
  1474.     register int status = ACCESS_CODE_OK;
  1475.     char nbuf[STRINGLENGTH];
  1476.     static char errbuf[STRINGLENGTH];
  1477. #if    CMUCS
  1478.     int *grps;
  1479. #endif    /* CMUCS */
  1480.     char *p;
  1481.  
  1482.     if (namep == NULL) {
  1483.         pwd = getpwuid (fileuid);
  1484.         if (pwd == NULL) {
  1485.             (void) sprintf (errbuf,"Reason:  Unknown user id %d",
  1486.                 fileuid);
  1487.             return (errbuf);
  1488.         }
  1489.         grp = getgrgid (filegid);
  1490.         if (grp)  group = strcpy (nbuf,grp->gr_name);
  1491.         else  group = NULL;
  1492.         account = NULL;
  1493.         pswdp = NULL;
  1494.     } else {
  1495.         (void) strcpy (nbuf,namep);
  1496.         account = group = index (nbuf,',');
  1497.         if (group != NULL) {
  1498.             *group++ = '\0';
  1499.             account = index (group,',');
  1500.             if (account != NULL) {
  1501.                 *account++ = '\0';
  1502.                 if (*account == '\0')  account = NULL;
  1503.             }
  1504.             if (*group == '\0')  group = NULL;
  1505.         }
  1506.         pwd = getpwnam (nbuf);
  1507.         if (pwd == NULL) {
  1508.             (void) sprintf (errbuf,"Reason:  Unknown user %s",
  1509.                 nbuf);
  1510.             return (errbuf);
  1511.         }
  1512.         if (strcmp (nbuf,DEFUSER) == 0)
  1513.             pswdp = NULL;
  1514.         else
  1515.             pswdp = passwordp ? passwordp : "";
  1516. #ifdef AFS
  1517.                 if (strcmp (nbuf,DEFUSER) != 0) {
  1518.                         char *reason;
  1519.                         setpag(); /* set a pag */
  1520.                         if (ka_UserAuthenticate(pwd->pw_name, "", 0,
  1521.                                                 pswdp, 1, &reason)) {
  1522.                                 (void) sprintf (errbuf,"AFS authentication failed, %s",
  1523.                                                 reason);
  1524.                                 logerr ("Attempt by %s; %s",
  1525.                                         nbuf, errbuf);
  1526.                                 return (errbuf);
  1527.                         }
  1528.                 }
  1529. #endif
  1530.     }
  1531.     if (getuid () != 0) {
  1532.         if (getuid () == pwd->pw_uid)
  1533.             return (NULL);
  1534.         if (strcmp (pwd->pw_name,DEFUSER) == 0)
  1535.             return (NULL);
  1536.         logerr ("Fileserver not superuser");
  1537.         return ("Reason:  fileserver is not running privileged");
  1538.     }
  1539. #if    CMUCS
  1540.     tlc.tlc_hostid = TLC_UNKHOST;
  1541.     tlc.tlc_ttyid = TLC_UNKTTY;
  1542.     if (okaccess(pwd->pw_name,ACCESS_TYPE_SU,0,-1,tlc) != 1)
  1543.         status = ACCESS_CODE_DENIED;
  1544.     else {
  1545.         grp = NULL;
  1546.         acc = NULL;
  1547.         status = oklogin(pwd->pw_name,group,&account,pswdp,&pwd,&grp,&acc,&grps);
  1548.         if (status == ACCESS_CODE_OK) {
  1549.             if ((p = okpassword(pswdp,pwd->pw_name,pwd->pw_gecos)) != NULL)
  1550.                 status = ACCESS_CODE_INSECUREPWD;
  1551.         }
  1552.     }
  1553. #else    /* CMUCS */
  1554.     status = ACCESS_CODE_OK;
  1555.     if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
  1556.         if (strcmp(pwd->pw_passwd,(char *)crypt(pswdp,pwd->pw_passwd)))
  1557.             status = ACCESS_CODE_BADPASSWORD;
  1558. #endif    /* CMUCS */
  1559.     switch (status) {
  1560.     case ACCESS_CODE_OK:
  1561.         break;
  1562.     case ACCESS_CODE_BADPASSWORD:
  1563.         p = "Reason:  Invalid password";
  1564.         break;
  1565. #if    CMUCS
  1566.     case ACCESS_CODE_INSECUREPWD:
  1567.         (void) sprintf (errbuf,"Reason:  %s",p);
  1568.         p = errbuf;
  1569.         break;
  1570.     case ACCESS_CODE_DENIED:
  1571.         p = "Reason:  Access denied";
  1572.         break;
  1573.     case ACCESS_CODE_NOUSER:
  1574.         p = errbuf;
  1575.         break;
  1576.     case ACCESS_CODE_ACCEXPIRED:
  1577.         p = "Reason:  Account expired";
  1578.         break;
  1579.     case ACCESS_CODE_GRPEXPIRED:
  1580.         p = "Reason:  Group expired";
  1581.         break;
  1582.     case ACCESS_CODE_ACCNOTVALID:
  1583.         p = "Reason:  Invalid account";
  1584.         break;
  1585.     case ACCESS_CODE_MANYDEFACC:
  1586.         p = "Reason:  User has more than one default account";
  1587.         break;
  1588.     case ACCESS_CODE_NOACCFORGRP:
  1589.         p = "Reason:  No account for group";
  1590.         break;
  1591.     case ACCESS_CODE_NOGRPFORACC:
  1592.         p = "Reason:  No group for account";
  1593.         break;
  1594.     case ACCESS_CODE_NOGRPDEFACC:
  1595.         p = "Reason:  No group for default account";
  1596.         break;
  1597.     case ACCESS_CODE_NOTGRPMEMB:
  1598.         p = "Reason:  Not member of group";
  1599.         break;
  1600.     case ACCESS_CODE_NOTDEFMEMB:
  1601.         p = "Reason:  Not member of default group";
  1602.         break;
  1603.     case ACCESS_CODE_OOPS:
  1604.         p = "Reason:  Internal error";
  1605.         break;
  1606. #endif    /* CMUCS */
  1607.     default:
  1608.         (void) sprintf (p = errbuf,"Reason:  Status %d",status);
  1609.         break;
  1610.     }
  1611.     if (pwd == NULL)
  1612.         return (p);
  1613.     if (status != ACCESS_CODE_OK) {
  1614.         logerr ("Login failure for %s",pwd->pw_name);
  1615.         logerr ("%s",p);
  1616. #if    CMUCS
  1617.         logaccess (pwd->pw_name,ACCESS_TYPE_SUP,status,0,-1,tlc);
  1618. #endif    /* CMUCS */
  1619.         return (p);
  1620.     }
  1621. #if    CMUCS
  1622.     if (setgroups (grps[0], &grps[1]) < 0)
  1623.         logerr ("setgroups: %%m");
  1624.     if (setgid ((gid_t)grp->gr_gid) < 0)
  1625.         logerr ("setgid: %%m");
  1626.     if (setuid ((uid_t)pwd->pw_uid) < 0)
  1627.         logerr ("setuid: %%m");
  1628. #else   /* CMUCS */
  1629.     if (initgroups (pwd->pw_name,pwd->pw_gid) < 0)
  1630.         return("Error setting group list");
  1631.     if (setgid (pwd->pw_gid) < 0)
  1632.         logerr ("setgid: %%m");
  1633.     if (setuid (pwd->pw_uid) < 0)
  1634.         logerr ("setuid: %%m");
  1635. #endif    /* CMUCS */
  1636.     return (NULL);
  1637. }
  1638.  
  1639. #if __STDC__
  1640. goaway (char *fmt,...)
  1641. #else
  1642. /*VARARGS*//*ARGSUSED*/
  1643. goaway (va_alist)
  1644. va_dcl
  1645. #endif
  1646. {
  1647. #if !__STDC__
  1648.     register char *fmt;
  1649. #endif
  1650.     char buf[STRINGLENGTH];
  1651.     va_list ap;
  1652.  
  1653.     (void) netcrypt ((char *)NULL);
  1654. #if __STDC__
  1655.     va_start(ap,fmt);
  1656. #else
  1657.     va_start(ap);
  1658.     fmt = va_arg(ap,char *);
  1659. #endif
  1660.     vsnprintf(buf, sizeof(buf), fmt, ap);
  1661.     va_end(ap);
  1662.     goawayreason = salloc (buf);
  1663.     (void) msggoaway ();
  1664.     logerr ("%s",buf);
  1665.     longjmp (sjbuf,TRUE);
  1666. }
  1667.  
  1668. char *fmttime (time)
  1669. long time;
  1670. {
  1671.     static char buf[STRINGLENGTH];
  1672.     int len;
  1673.  
  1674.     (void) strcpy (buf,ctime (&time));
  1675.     len = strlen(buf+4)-6;
  1676.     (void) strncpy (buf,buf+4,len);
  1677.     buf[len] = '\0';
  1678.     return (buf);
  1679. }
  1680.  
  1681. /*
  1682.  * Determine whether the file referenced by the file descriptor 'handle' can
  1683.  * be trusted, namely is it a file resident in the local file system.
  1684.  *
  1685.  * The main method of operation is to perform operations on the file
  1686.  * descriptor so that an attempt to spoof the checks should fail, for
  1687.  * example renamimg the file from underneath us and/or changing where the
  1688.  * file lives from underneath us.
  1689.  *
  1690.  * returns: -1 for error, indicating that we can not tell
  1691.  *         0 for file is definately not local, or it is an RFS link
  1692.  *         1 for file is local and can be trusted
  1693.  *
  1694.  * Side effect: copies the stat information into the supplied buffer,
  1695.  * regardless of the type of file system the file resides.
  1696.  *
  1697.  * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
  1698.  * UFS, where the latter is considered a trusted file.  We assume that the
  1699.  * caller has disabled link following and will detect an attempt to access
  1700.  * a file through an RFS link, except in the case the the last component is
  1701.  * an RFS link.  With link following disabled, the last component itself is
  1702.  * interpreted as a regular file if it is really an RFS link, so we
  1703.  * disallow the RFS link identified by group "symlink" and mode "IEXEC by
  1704.  * owner only". An AFS file is
  1705.  * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
  1706.  * ioctls which operate on a file descriptor.  Note, this AFS ioctl is
  1707.  * implemented in the cache manager, so the decision does not involve a
  1708.  * query with the AFS file server.  An NFS file is detected by looking at
  1709.  * the major device number and seeing if it matches the known values for
  1710.  * MACH NSF/Sun OS 3.x or Sun OS 4.x.
  1711.  *
  1712.  * Having the fstatfs() system call would make this routine easier and
  1713.  * more reliable.
  1714.  *
  1715.  * Note, in order to make the checks simpler, the file referenced by the
  1716.  * file descriptor can not be a BSD style symlink.  Even with symlink
  1717.  * following of the last path component disabled, the attempt to open a
  1718.  * file which is a symlink will succeed, so we check for the BSD symlink
  1719.  * file type here.  Also, the link following on/off and RFS file types
  1720.  * are only relevant in a MACH environment. 
  1721.  */
  1722. #ifdef    AFS
  1723. #include <sys/viceioctl.h>
  1724. #endif
  1725.  
  1726. #define SYMLINK_GRP 64
  1727.  
  1728. int local_file(handle, sinfo)
  1729. int handle;
  1730. struct stat *sinfo;
  1731. {
  1732.     struct stat sb;
  1733. #ifdef    VIOCIGETCELL
  1734.     /*
  1735.      * dummies for the AFS ioctl
  1736.      */
  1737.     struct ViceIoctl vdata;
  1738.     char cellname[512];
  1739. #endif    /* VIOCIGETCELL */
  1740.  
  1741.     if (fstat(handle, &sb) < 0)
  1742.         return(-1);
  1743.     if (sinfo != NULL)
  1744.         *sinfo = sb;
  1745.  
  1746. #if    CMUCS
  1747.     /*
  1748.      * If the following test succeeds, then the file referenced by
  1749.      * 'handle' is actually an RFS link, so we will not trust it.
  1750.      * See <sys/inode.h>.
  1751.      */
  1752.     if (sb.st_gid == SYMLINK_GRP
  1753.         && (sb.st_mode & (S_IFMT|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
  1754.             == (S_IFREG|S_IEXEC))
  1755.         return(0);
  1756. #endif    /* CMUCS */
  1757.  
  1758.     /*
  1759.      * Do not trust BSD style symlinks either.
  1760.      */
  1761.     if ((sb.st_mode & S_IFMT) == S_IFLNK)
  1762.         return(0);
  1763.  
  1764. #ifdef    VIOCIGETCELL
  1765.     /*
  1766.      * This is the VIOCIGETCELL ioctl, which takes an fd, not
  1767.      * a path name.  If it succeeds, then the file is in AFS.
  1768.      *
  1769.      * On failure, ENOTTY indicates that the file was not in
  1770.      * AFS; all other errors are pessimistically assumed to be
  1771.      * a temporary AFS error.
  1772.      */
  1773.     vdata.in_size = 0;
  1774.     vdata.out_size = sizeof(cellname);
  1775.     vdata.out = cellname;
  1776.     if (ioctl(handle, VIOCIGETCELL, (char *)&vdata) != -1)
  1777.         return(0);
  1778.     if (errno != ENOTTY)
  1779.         return(-1);
  1780. #endif    /* VIOCIGETCELL */
  1781.  
  1782.     /*
  1783.      * Verify the file is not in NFS.
  1784.      *
  1785.      * Our current implementation and Sun OS 3.x use major device
  1786.      * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
  1787.      * determined this empirically -- DLC).  Without a fstatfs()
  1788.      * system call, this will have to do for now.
  1789.      */
  1790.     if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
  1791.         return(0);
  1792.  
  1793.     return(1);
  1794. }
  1795.  
  1796. /*
  1797.  * Companion routine for ensuring that a local file can be trusted.  Compare
  1798.  * various pieces of the stat information to make sure that the file can be
  1799.  * trusted.  Returns true for stat information which meets the criteria
  1800.  * for being trustworthy.  The main paranoia is to prevent a hard link to
  1801.  * a root owned file.  Since the link could be removed after the file is
  1802.  * opened, a simply fstat() can not be relied upon.  The two stat buffers
  1803.  * for comparison should come from a stat() on the file name and a following
  1804.  * fstat() on the open file.  Some of the following checks are also an
  1805.  * additional level of paranoia.  Also, this test will fail (correctly) if
  1806.  * either or both of the stat structures have all fields zeroed; typically
  1807.  * due to a stat() failure.
  1808.  */
  1809.  
  1810.  
  1811. int stat_info_ok(sb1, sb2)
  1812. struct stat *sb1, *sb2;
  1813. {
  1814.     return (sb1->st_ino == sb2->st_ino &&    /* Still the same file */
  1815.         sb1->st_dev == sb2->st_dev &&    /* On the same device */
  1816.         sb1->st_mode == sb2->st_mode &&     /* Perms (and type) same */
  1817.         (sb1->st_mode & S_IFMT) == S_IFREG && /* Only allow reg files */
  1818.         (sb1->st_mode & 077) == 0 &&    /* Owner only perms */
  1819.         sb1->st_nlink == sb2->st_nlink &&    /* # hard links same... */
  1820.         sb1->st_nlink == 1 &&        /* and only 1 */
  1821.         sb1->st_uid == sb2->st_uid &&    /* owner and ... */
  1822.         sb1->st_gid == sb2->st_gid &&    /* group unchanged */
  1823.         sb1->st_mtime == sb2->st_mtime &&    /* Unmodified between stats */
  1824.         sb1->st_ctime == sb2->st_ctime);    /* Inode unchanged.  Hopefully
  1825.                            a catch-all paranoid test */
  1826. }
  1827.  
  1828. #if MACH
  1829. /*
  1830.  * Twiddle symbolic/RFS link following on/off.  This is a no-op in a non
  1831.  * CMUCS/MACH environment.  Also, the setmodes/getmodes interface is used
  1832.  * mainly because it is simpler than using table(2) directly.
  1833.  */
  1834. #include <sys/table.h>
  1835.  
  1836. int link_nofollow(on)
  1837. int on;
  1838. {
  1839.     static int modes = -1;
  1840.  
  1841.     if (modes == -1 && (modes = getmodes()) == -1)
  1842.         return(-1);
  1843.     if (on)
  1844.         return(setmodes(modes | UMODE_NOFOLLOW));
  1845.     return(setmodes(modes));
  1846. }
  1847. #else    /* MACH */
  1848. /*ARGSUSED*/
  1849. int link_nofollow(on)
  1850. int on;
  1851. {
  1852.     return(0);
  1853. }
  1854. #endif    /* MACH */
  1855.